package com.hzqy.web.interceptor;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONObject;

public class ParameterSecurityCheckInterceptor implements HandlerInterceptor{

	protected final Logger LOG = LoggerFactory.getLogger(getClass());
	
	private static final List<String> INVALID_STRING_LIST;
	
	//防止sql注入正则表达式
	private static final Pattern PREVENT_SQL_INJECT_REGREP = 
			Pattern.compile(
					"(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)",
					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNICODE_CASE
			);
	
	//防止xss注入正则表达式
	private static final Pattern PREVENT_XSS_INJECT_REGREP = 
			Pattern.compile(
					//"[%--`~!@#$^&*()=|{}':;',\\\\[\\\\].<>/?~！@#￥……&*（）——| {}【】‘；：”“'。，、？]";
					"[#]",
					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL
			);

	private static Pattern[] PREVENT_XSS_INJECT_REGREPS = new Pattern[]{
			// Script fragments
			Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
			// src='...'
			Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
			Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
			// lonely script tags
			Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
			Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
			// eval(...)
			Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
			// expression(...)
			Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
			// javascript:...
			Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
			// vbscript:...
			Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
			// onl oad(...)=...
			Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
			//现场安全测试增加校验
			Pattern.compile("alert(.*?)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
			Pattern.compile("<", Pattern.MULTILINE | Pattern.DOTALL),
			Pattern.compile(">", Pattern.MULTILINE | Pattern.DOTALL),
			// Pattern.Pattern("(document|onload|eval|script|img|svg|onerror|javascript|alert)\\\\b")
			Pattern.compile("((alert|on\\w+|function\\s+\\w+)\\s*\\(\\s*(['+\\d\\w](,?\\s*['+\\d\\w]*)*)*\\s*\\))"),
			//Checks any html tags i.e. <script, <embed, <object etc.
			Pattern.compile("(<(script|iframe|embed|frame|frameset|object|img|applet|body|html|style|layer|link|ilayer|meta|bgsound))")
	};


	
	
	static {
		String[] string_arr = new String[] {
				"--", "//", "#",
				"xp_shell", "||", "'", 
				"\""

		};
		
		INVALID_STRING_LIST = new ArrayList<String>(string_arr.length);
		for(String word : string_arr) {
			INVALID_STRING_LIST.add(word);
		}
		
	}
	
	
	
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception e)
			throws Exception {
		
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView)
			throws Exception {
		
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
		//LOG.debug("ParameterSecurityCheckInterceptor拦截 " + request.getRequestURI());
		Map<String, String[]> paramMap = request.getParameterMap();
		Iterator<Entry<String, String[]>> iterator = paramMap.entrySet().iterator();
		while(iterator.hasNext()) {
			Entry<String, String[]> entry = iterator.next();
			for(String val : entry.getValue()) {
				int flag = checkString(val);
				if(flag != 0) {
					LOG.debug("find invalid param name: " + entry.getKey() +", value: " + val + ", flag: " + flag);
					Map<String, Object> resultMap = new HashMap<String, Object>();
					resultMap.put("flag", flag);
					resultMap.put("invalid_param_name", entry.getKey());
					resultMap.put("invalid_param_value", val);
					resultMap.put("message_main", "参数中存在非法的字符或字符串！请参考com.hzqy.web.interceptor.ParameterSecurityCheckInterceptor");
					
					response.setContentType("text/html;charset=utf-8");
					PrintWriter out = response.getWriter();
					out.print(JSONObject.toJSONString(resultMap));
					out.close();
					return false;
				}
			}
		}
		
		
		return true;
	}

	
	/*public static void main(String[] args) {
		System.out.println(checkString("《\"style:=border: 1px solid red_\"人民的名义-sss》"));
		//Map<String, Object> map = new HashMap<String, Object>();
	}*/
	
	private final int checkString(String str) {
		if(str == null || "".equals(str.trim())) {
			return 0;
		}
		
//		if(str.length() > 8) {
//			boolean hasXSS = hasXSS(str);
//			if(hasXSS) return -1;
//		}

		LOG.debug("检测参数值: " + str);
		if(PREVENT_SQL_INJECT_REGREP.matcher(str).find()) {
			return -3;
		}

		for (Pattern scriptPattern : PREVENT_XSS_INJECT_REGREPS) {
			if(scriptPattern.matcher(str).find()) {
				LOG.debug("检测出xss攻击 pattern:" + scriptPattern.pattern() + " value: " + str);
				return -2;
			}
		}

//		if(PREVENT_XSS_INJECT_REGREP.matcher(str).find()) {
//			return -2;
//		}

		return 0;
	}
	
	
//
//	/**
//	 * 检测xss注入
//	 */
//	private static boolean hasXSS(String value) {
//		boolean hasXSS = false;
//		if (value != null) {
//			// NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to
//			// avoid encoded attacks.
//			// value = ESAPI.encoder().canonicalize(value);
//			// Avoid null characters
//			value = value.replaceAll("", "");
//			// Avoid anything between script tags
//			Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Avoid anything in a src="http://www.yihaomen.com/article/java/..." type of e­xpression
//			scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Remove any lonesome </script> tag
//			scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Remove any lonesome <script ...> tag
//			scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Avoid eval(...) e­xpressions
//			scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Avoid e­xpression(...) e­xpressions
//			scriptPattern = Pattern.compile("e­xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Avoid javascript:... e­xpressions
//			scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Avoid vbscript:... e­xpressions
//			scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//			// Avoid onload= e­xpressions
//			scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
//			hasXSS = scriptPattern.matcher(value).matches();
//			if(hasXSS) return hasXSS;
//		}
//		return hasXSS;
//	}
//
//
}
